package fi.jab.jesbtor.views;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.BasicExtendedMetaData;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.mylyn.zest.core.viewers.EntityConnectionData;
import org.eclipse.mylyn.zest.core.viewers.GraphViewer;
import org.eclipse.mylyn.zest.core.viewers.IGraphEntityContentProvider;
import org.eclipse.mylyn.zest.core.widgets.ZestStyles;
import org.eclipse.mylyn.zest.layouts.LayoutStyles;
import org.eclipse.mylyn.zest.layouts.algorithms.RadialLayoutAlgorithm;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.xsd.XSDFactory;
import org.eclipse.xsd.XSDSchema;

import fi.jab.esb.config.xml.ActionType;
import fi.jab.esb.config.xml.ActionsType;
import fi.jab.esb.config.xml.Bus;
import fi.jab.esb.config.xml.BusProvider;
import fi.jab.esb.config.xml.DocumentRoot;
import fi.jab.esb.config.xml.JbossesbType;
import fi.jab.esb.config.xml.JmsBusType;
import fi.jab.esb.config.xml.JmsListenerType;
import fi.jab.esb.config.xml.JmsProviderType;
import fi.jab.esb.config.xml.Listener;
import fi.jab.esb.config.xml.Provider;
import fi.jab.esb.config.xml.ProvidersType;
import fi.jab.esb.config.xml.ServiceType;
import fi.jab.esb.config.xml.ServicesType;
import fi.jab.esb.config.xml.XmlPackage;
import fi.jab.esb.config.xml.util.XmlResourceFactoryImpl;

public class JBossEsbVizualizer extends ViewPart implements ISelectionListener, IPartListener2 {

	public static final String ID = "fi.jab.jesbtor.views.JBossEsbVizualizer";

	GraphViewer viewer = null;

	private Composite parent;

	public JbossesbType jbossEsb;

	class MyStaticContentProvider implements IGraphEntityContentProvider {

		@SuppressWarnings("unchecked")
		public Object[] getConnectedTo(Object entity) {

			if (entity instanceof ServiceType) {
				ServiceType st = (ServiceType) entity;

				List l = new ArrayList(st.getListeners().getListener());
				l.addAll(st.getActions().getAction());

				return l.toArray();

			} else if (entity instanceof ActionsType) {
				ActionsType at = (ActionsType) entity;
				EList<ActionType> action = at.getAction();
				ActionsType[] actions = new ActionsType[action.size()];

				action.toArray(actions);

				return actions;
			} else if (entity instanceof ActionsType) {
				ActionsType at = (ActionsType) entity;
				EList<ActionType> action = at.getAction();
				ActionsType[] actions = new ActionsType[action.size()];

				action.toArray(actions);

				return actions;
			} else if (entity instanceof JmsProviderType) {
				JmsProviderType a = (JmsProviderType) entity;
				List l = a.getBus();

				return l.toArray();

			} else if (entity instanceof JmsListenerType) {
				JmsListenerType a = (JmsListenerType) entity;
				String busidref = a.getBusidref();
				List<Provider> ps = jbossEsb.getProviders().getProvider();
				for (Provider provider : ps) {
					if (provider instanceof BusProvider) {
						BusProvider bp = (BusProvider) provider;
						List<Bus> busses = bp.getBus();
						for (Bus bus : busses) {
							if (bus.getBusid().equals(busidref)) {
								List lll = new ArrayList();
								lll.add(bus);
								return lll.toArray();
							}
						}
					}
				}
				return null;

			}

			return null;
		}

		private Object[] getProviders() {
			ProvidersType providers = jbossEsb.getProviders();
			EList<Provider> prods = providers.getProvider();
			return prods.toArray();

		}

		@SuppressWarnings("unchecked")
		private Object[] getServices() {
			ServicesType providers = jbossEsb.getServices();
			List all = new ArrayList();

			List<ServiceType> prods = providers.getService();

			for (ServiceType serviceType : prods) {

				List<Listener> listeners = serviceType.getListeners().getListener();
				all.addAll(listeners);

				List<ActionType> actions = serviceType.getActions().getAction();
				all.addAll(actions);

			}

			all.addAll(prods);
			return all.toArray();

		}

		@SuppressWarnings("unchecked")
		public Object[] getElements(Object inputElement) {
			if (jbossEsb == null) {
				return null;
			}

			ArrayList al = new ArrayList();
			al.addAll(Arrays.asList(getProviders()));
			al.addAll(Arrays.asList(getServices()));

			return al.toArray();

		}

		public double getWeight(Object entity1, Object entity2) {
			return 0;
		}

		public void dispose() {

		}

		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {

		}
	}

	static class MyStaticLabelProvider extends LabelProvider {
		final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING);

		public MyStaticLabelProvider() {
			// TODO Auto-generated constructor stub
		}

		public Image getImage(Object element) {

			if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) {
				return image;
			}

			return null;
		}

		public String getText(Object element) {

			if (element instanceof ServiceType) {
				ServiceType st = (ServiceType) element;
				return st.getCategory() + ":" + st.getName();

			} else if (element instanceof ActionType) {
				ActionType at = (ActionType) element;
				String a = at.getName();
				a += " " + at.getClass_();
				a += "." + at.getProcess();
				return a;

			} else if (element instanceof JmsProviderType) {
				JmsProviderType at = (JmsProviderType) element;
				String a = at.getName();
				return a;

			} else if (element instanceof JmsBusType) {
				JmsBusType at = (JmsBusType) element;
				String a = at.getJmsMessageFilter().getDestName();
				return a;

			} else if (element instanceof JmsListenerType) {
				JmsListenerType at = (JmsListenerType) element;
				String a = at.getName();
				return a;

			} else if (element instanceof EntityConnectionData) {
				EntityConnectionData ecd = (EntityConnectionData) element;
				if (ecd.source instanceof JmsProviderType && ecd.dest instanceof JmsBusType) {
					JmsBusType j = (JmsBusType) ecd.dest;
					return null; // j.getJmsMessageFilter().getDestName();
				}

				if (ecd.dest instanceof JmsListenerType && ecd.source instanceof JmsBusType) {
					JmsListenerType j = (JmsListenerType) ecd.dest;
					return j.getBusidref();

				}

				if (ecd.dest instanceof JmsListenerType && ecd.source instanceof ServiceType) {
					JmsListenerType j = (JmsListenerType) ecd.dest;
					return j.isIsGateway() == true ? "gateway" : null;

				}

			}

			return null;
		}

	}

	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	public void createPartControl(Composite parent) {
		this.parent = parent;

		getViewSite().getPage().addPartListener(this);
		changeContents();
	}

	private void setViewer(IFile ifile) {

		if (parent == null || ifile == null)
			return;

		// http://www.theserverside.com/tt/articles/article.tss?l=BindingXMLJava
		String filename = ifile.getLocationURI().toString();

		ResourceSet resourceSet = new ResourceSetImpl();
		final ExtendedMetaData extendedMetaData = new BasicExtendedMetaData(resourceSet.getPackageRegistry());
		resourceSet.getLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData);

		resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XmlResourceFactoryImpl());
		resourceSet.getPackageRegistry().put(XmlPackage.eNS_URI, XmlPackage.eINSTANCE);

		Resource resource = resourceSet.getResource(URI.createURI(filename), true);

		DocumentRoot documentRoot = (DocumentRoot) resource.getContents().get(0);
		JbossesbType rootTreeNode = documentRoot.getJbossesb();

		this.jbossEsb = rootTreeNode;

		if (viewer == null) {
			viewer = new GraphViewer(parent, SWT.NONE);
			viewer.setLayoutAlgorithm(new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
			viewer.setNodeStyle(ZestStyles.NODES_HIGHLIGHT_ADJACENT);

			viewer.setContentProvider(new MyStaticContentProvider());
			viewer.setLabelProvider(new MyStaticLabelProvider());
			viewer.setInput(new Object());
		} else {
			// viewer.setLayoutAlgorithm(new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
			viewer.refresh(true);
		}

	}

	public IEditorPart getActiveEditor() {
		try {
			IEditorPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
			return part;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {

		viewer.getControl().setFocus();

	}

	@Override
	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
		if (selection instanceof IStructuredSelection) {
			Object first = ((IStructuredSelection) selection).getFirstElement();
			// System.out.println(first);
		}
	}

	private void changeContents() {

		IEditorPart part = getActiveEditor();
		if (part == null)
			return;
		IEditorInput input = part.getEditorInput();
		if (input == null)
			return;

		IFile ifile = (IFile) input.getAdapter(IFile.class);
		if (ifile != null) {
			try {
				// FIXME don't depend on filename
				if (!"jboss-esb.xml".equals(ifile.getName()))
					return;

				setViewer(ifile);

			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	@Override
	public void partActivated(IWorkbenchPartReference iworkbenchpartreference) {
		// TODO Auto-generated method stub
		try {
			IEditorPart ieditor = iworkbenchpartreference.getPage().getActiveEditor();
			if (ieditor != null) {
				changeContents();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void partBroughtToTop(IWorkbenchPartReference iworkbenchpartreference) {
		// TODO Auto-generated method stub
		System.out.println(iworkbenchpartreference);
		try {
			IEditorPart ieditor = iworkbenchpartreference.getPage().getActiveEditor();
			if (ieditor != null) {
				changeContents();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void partClosed(IWorkbenchPartReference iworkbenchpartreference) {
		// TODO Auto-generated method stub
		System.out.println(iworkbenchpartreference);
	}

	@Override
	public void partDeactivated(IWorkbenchPartReference iworkbenchpartreference) {

	}

	@Override
	public void partHidden(IWorkbenchPartReference iworkbenchpartreference) {
		// TODO Auto-generated method stub
		System.out.println(iworkbenchpartreference);
	}

	@Override
	public void partInputChanged(IWorkbenchPartReference iworkbenchpartreference) {
		// TODO Auto-generated method stub
		System.out.println(iworkbenchpartreference);
	}

	@Override
	public void partOpened(IWorkbenchPartReference iworkbenchpartreference) {
		System.out.println(iworkbenchpartreference);

	}

	@Override
	public void partVisible(IWorkbenchPartReference iworkbenchpartreference) {
		// TODO Auto-generated method stub
		System.out.println(iworkbenchpartreference);
	}
}